package animal;

/**
 * Ein Lauftier ist die Superklassen von den Tieren die erzeugt werden k�nnen
 * 
 * @author Shkelqim Turkaj
 * @version 3
 */

import static java.lang.Math.PI;
import static java.lang.Math.atan;
import static java.lang.Math.cos;
import static java.lang.Math.sin;
import sim.AmeisenSimulation;
import sim.SimulationParameters;
import ui.AntSimRenderer;
import ui.Grafikobjekt;
import util.Hilfsklasse;

public abstract class Lauftier extends Grafikobjekt {

	public static final int UMDREHEN = 10;
	public double SCHRITTLAENGE = 0;

	private SimulationParameters simParam = new SimulationParameters();
	private boolean lebendig = true;
	private long todesZeitpunkt;
	private double maxGeschwindigkeit;
	private String bezeichnung;
	private long lastTurn;
	private boolean isKeineGefahr;

	/**
	 * Verhindert, dass das Lauftier das Anzeigefeld verl�sst. Befindett sich
	 * das Lauftier zu nahe am Rand oder au�erhalb, wird sie wieder ins Feld
	 * gesetzt. Ihre Blickrichtung (Drehung) wird um 180� ins Feldesinnere
	 * gedreht.
	 * 
	 * @param anzeigefeld
	 *            Das Anzeigefeld, auf dem sich das Lauftier befindet.
	 */
	public void bleibeImAnzeigefeld(SimulationParameters parameters,
			AntSimRenderer renderer) {

		int hoehe = parameters.getWorldHeight();
		int breite = parameters.getWorldWidth();

		// hoehe = renderer.getHeight();
		// breite = renderer.getWidth();

		if (getY() > hoehe - UMDREHEN) {
			setY(hoehe - UMDREHEN);
			setDrehung(getDrehung() + PI);
		} else if (getX() < UMDREHEN) {
			setX(UMDREHEN);
			setDrehung(getDrehung() + PI);
		} else if (getY() < UMDREHEN) {
			setY(UMDREHEN);
			setDrehung(getDrehung() + PI);
		} else if (getX() > breite - UMDREHEN) {
			setX(breite - UMDREHEN);
			setDrehung(getDrehung() + PI);
		}

	}

	/**
	 * Diese Methode versetzt die Ameise um einen Schritt in Richtung inder die
	 * Ameisen schauen.
	 * 
	 */
	private void laufInDrehRichtung(double schrittlaenge2) {
		setX(getX() + (Hilfsklasse.cosinus(getDrehung()) * schrittlaenge2));
		setY(getY() - (Hilfsklasse.sinus(getDrehung()) * schrittlaenge2));
	}

	/**
	 * Laesst die Lauftier einen Schritt zufaelliger Geschwindigkeit entgegen
	 * der Blickrichtung machen. Moegliche Werte f�r die Schrittl�nge werden
	 * dem Intervall [kleinsterSchritt, groessterSchritt[ entnommen.
	 */
	public void schrittEntgegenBlickrichtung() {
		setY(getY()
				- (Hilfsklasse.cosinus(getDrehung()) * SCHRITTLAENGE + Math.PI));
		setX(getX()
				+ (Hilfsklasse.cosinus(getDrehung()) * SCHRITTLAENGE + Math.PI));
	}

	/**
	 * L�sst das Lauftier einen Schritt zufaelliger Geschwindigkeit in
	 * Blickrichtung machen. M�gliche Werte f�r die Schrittl�nge werden
	 * dem Intervall [kleinsterSchritt, groessterSchritt[ entnommen.
	 * Zus�tzlich kann der Wertebereich Zufallswert f�r die Blickrichtung
	 * (Drehung) beliebig eingestellt werden.
	 * 
	 * @param drehungLinks
	 *            Maximaler Wert f�r die Linksdrehung.
	 * @param drehungRechts
	 *            Maximaler Wert f�r die Rechtsdrehung.
	 */
	public void zufaelligerSchritt(double drehungLinks, double drehungRechts) {
		setDrehung(getDrehung()
				+ Hilfsklasse
						.gradInRadiant(Hilfsklasse
								.getZufallsDouble(2 * drehungRechts + 1)
								- drehungLinks));
		laufInDrehRichtung(SCHRITTLAENGE);
	}

	/**
	 * Setzt die Blickrichtung (Drehung) des Lauftiers in Richtung Zielobjekt.
	 * 
	 * @param x
	 *            X-Koordinate des Zielobjekts.
	 * @param y
	 *            Y-Koordinate des Zielobjekts.
	 */
	public void bestimmtesZielAnvisieren(double x, double y) {

		if (getX() < x) {
			setDrehung(atan((y - getY()) / (getX() - x)));
		} else if (getX() > x) {
			setDrehung(atan((y - getY()) / (getX() - x)) + PI);
		} else if (getY() < y) {
			setDrehung(1.5 * PI);
		} else if (getY() > y) {
			setDrehung(0.5 * PI);
		}
	}

	/**
	 * Setzt die Blickrichtung (Drehung) entgegen des Fresstiers.
	 * 
	 * @param x
	 *            X-Koordinate des Zielobjekts.
	 * @param y
	 *            Y-Koordinate des Zielobjekts.
	 */
	public void bestimmtesZielMeiden(double x, double y) {
		// TODO
		if (getX() < x) {
			setDrehung(atan((y - getY()) / (getX() - x)) + PI);
		} else if (getX() > x) {
			setDrehung(atan((y - getY()) / (getX() - x)));
		} else if (getY() < y) {
			setDrehung(1.5 * 2 * PI);
		} else if (getY() > y) {
			setDrehung(0.5 * 2 * PI);
		}
	}

	
	
	/**
	 * Diese Methode testet, ob ein Lauftier sich in der N�he des
	 * �bergebenen Punktes
	 * 
	 * @param x
	 *            X-Koordinate des Zielobjekts.
	 * @param y
	 *            Y-Koordinate des Zielobjekts.
	 * @param maximalerAbstand
	 *            Geschlossenes Intervall der zul�ssigen Entfernung.
	 * @return True, wenn der Abstand kleiner gleich dem maximal erlaubten
	 *         Abstand. False, wenn der Abstand echt gr��er dem maximal
	 *         erlaubten Abstand.
	 */
	public boolean istNahe(double x, double y, double maximalerAbstand) {
		return Hilfsklasse.ermittleAbstand(x, y, getX(), getY()) <= maximalerAbstand;
	}

	/**
	 * 
	 * @param a
	 * @param b
	 * @return
	 */
	public boolean vergleicheObSelbeKoordinaten(Lauftier a, Lauftier b) {
		if ((a.getX() == b.getX()) && (a.getY() == b.getY())) {
			return true;
		}
		return false;
	}

	/**
	 * Das Lauftier bewegt sich zufaellig innerhalb des Anzeigebereichs. die
	 * Richtung wird mit dem Blickwinkel (Drehung) festgelegt.
	 * 
	 * @param asim
	 *            Die Ameisensimulation.
	 * @param drehungLinks
	 *            Maximale Linksdrehung
	 * @param drehungRechts
	 *            Maximale Rechtsdrehung
	 */
	public void laufeZufaellig(AmeisenSimulation asim, double drehungLinks,
			double drehungRechts) {

		// Anzeigefeld anzeigefeld = asim.getAnzeigefeld();
		SimulationParameters parameters = asim.getSimulationParameters();
		bleibeImAnzeigefeld(parameters, asim.getAntSimRenderer());
		// if
		zufaelligerSchritt(drehungLinks, drehungRechts);

	}

	/**
	 * Die Ameise bewegt sich konzentriert auf ein Zielobjekt innerhalb des
	 * Anzeigebereichs zu.
	 * 
	 * @param asim
	 *            Die Ameisensimulation.
	 * @param x
	 *            X-Koordinate des Zielpunkts.
	 * @param y
	 *            Y-Koordinate des Zielpunkts.
	 */
	public void laufeGezielt(AmeisenSimulation simulation, double x, double y,
			double drehungLinks, double drehungRechts) {

		// Anzeigefeld anzeigefeld = simulation.getAnzeigefeld();

		bleibeImAnzeigefeld(simulation.getSimulationParameters(),
				simulation.getAntSimRenderer());

		bestimmtesZielAnvisieren(x, y);

		zufaelligerSchritt(drehungLinks, drehungRechts);

	}

	/**
	 * Die Ameise bewegt sich konzentriert von einem Zielobjekt innerhalb des
	 * Anzeigebereichs weg.
	 * 
	 * @param asim
	 *            Die Ameisensimulation.
	 * @param x
	 *            X-Koordinate des Zielpunkts.
	 * @param y
	 *            Y-Koordinate des Zielpunkts.
	 */
	public void flieheVorFresstier(AmeisenSimulation simulation, double x,
			double y, double drehungLinks, double drehungRechts) {

		bleibeImAnzeigefeld(simulation.getSimulationParameters(),
				simulation.getAntSimRenderer());

		bestimmtesZielMeiden(x, y);

		zufaelligerSchritt(drehungLinks, drehungRechts);

	}
 
	
	/**
	 * Setzt den Zustand des Lauftiers.
	 * 
	 * @param True
	 *            fuer lebendig, false fuer tot.
	 */
	public void setLebendig(boolean zustand) {
		lebendig = zustand;
		if (!zustand) {
			todesZeitpunkt = System.currentTimeMillis();
		}
	}

	public void setLebendig(boolean zustand, int killType) {
		lebendig = zustand;
		if (!zustand) {
			todesZeitpunkt = System.currentTimeMillis();
		}
	}

	/**
	 * Liefert den Zustand des Lauftiers.
	 * 
	 * @return True f�r lebendig, false f�r tot.
	 */
	public boolean getLebensZustand() {
		return lebendig;
	}

	/**
	 * Liefert den Todeszeitpunkt. Dieser kann 0 sein, falls das Tier lebt.
	 * 
	 * @return Todeszeitpunkt.
	 */
	public long getTodeszeitpunkt() {
		return todesZeitpunkt;
	}

	/**
	 * Setzt den Todeszeitpunkt neu.
	 * 
	 * @param Zeitpunkt
	 *            wann das Lauftier gestorben ist.
	 */
	public void setTodeszeitpunkt(long todesZeitpunkt) {
		this.todesZeitpunkt = todesZeitpunkt;
	}

	/**
	 * Gibt dem Lauftier eine eindeutige Bezeichnung.
	 * 
	 * @param bezeichnung
	 *            Die neue Bezeichnung.
	 */
	public void setBezeichnung(String bezeichnung) {
		this.bezeichnung = bezeichnung;
	}

	/**
	 * Liefert die Bezeichnung des Lauftiers.
	 * 
	 * @return Die Bezeichnung.
	 */
	public String getBezeichnung() {
		return bezeichnung;
	}

	public int getAnzahlVerspeisterAmeisen() {
		// TODO Auto-generated method stub
		return 0;
	}

	public boolean hatHunger() {
		// TODO Auto-generated method stub
		return false;
	}

	public boolean verspeisenDerAmeiseMoeglich(Ameise a) {
		// TODO Auto-generated method stub
		return false;
	}

	/**
	 * Setzt die durchschnittliche Schrittweite.
	 * 
	 * @param schrittweite
	 *            -die Schrittweite.
	 */
	public void setSchrittweite(double schrittweite) {
		SCHRITTLAENGE = schrittweite;
		laufInDrehRichtung(schrittweite);
	}

	/**
	 * Liefert die durchschnittliche Schrittweite.
	 * 
	 * @return Schrittweite.
	 */
	public double getSchrittweite() {
		return SCHRITTLAENGE;
	}

	/**
	 * @return the maxGeschwindigkeit
	 */
	public double getMaxGeschwindigkeit() {
		return maxGeschwindigkeit;
	}

	/**
	 * @param maxGeschwindigkeit
	 *            the maxGeschwindigkeit to set
	 */
	public void setMaxGeschwindigkeit(double maxGeschwindigkeit) {
		this.maxGeschwindigkeit = maxGeschwindigkeit;
	}

	/**
	 * @return the isGefaehrlich
	 */
	public boolean isKeineGefahr() {
		return isKeineGefahr;
	}

	/**
	 * @param isGefaehrlich the isGefaehrlich to set
	 */
	public void setKeineGefahr(boolean isKeineGefahr) {
		this.isKeineGefahr = isKeineGefahr;
	}

}
